package com.zyl.blog.processing.processor;

import com.zyl.blog.common.domain.file.bean.FileStorage;
import com.zyl.blog.common.utils.Extreme.LogUtil;
import com.zyl.blog.processing.exception.FileProcessingException;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * 抽象文件处理器基类
 * 提供通用的文件处理逻辑和模板方法模式
 * 
 * @author FinalFantasy
 * @version v1.0
 * @date 2025/09/01
 */
public abstract class AbstractFileProcessor implements FileProcessor {

    @Override
    public final boolean supports(String fileType) {
        if (fileType == null) {
            return false;
        }
        return getSupportedTypes().contains(fileType.toLowerCase());
    }

    @Override
    public final String extractText(MultipartFile file) {
        validateFile(file);
        
        try (InputStream inputStream = file.getInputStream()) {
            LogUtil.info("使用 {} 提取文本: {}", getProcessorName(), file.getOriginalFilename());
            return doExtractText(inputStream, getFileTypeFromName(file.getOriginalFilename()));
        } catch (IOException e) {
            LogUtil.error("文本提取失败: {}", e, file.getOriginalFilename());
            throw new FileProcessingException("文本提取失败: " + e.getMessage(), e);
        }
    }

    @Override
    public final String extractText(FileStorage fileStorage) {
        validateFileStorage(fileStorage);
        
        try {
            LogUtil.info("使用 {} 提取文本: {}", getProcessorName(), fileStorage.getOriginalFileName());
            return doExtractText(new File(fileStorage.getStoragePath()), fileStorage.getFileType());
        } catch (Exception e) {
            LogUtil.error("文本提取失败: {}", e, fileStorage.getOriginalFileName());
            throw new FileProcessingException("文本提取失败: " + e.getMessage(), e);
        }
    }

    @Override
    public final Map<String, Object> extractMetadata(MultipartFile file) {
        validateFile(file);
        
        try (InputStream inputStream = file.getInputStream()) {
            LogUtil.info("使用 {} 提取元数据: {}", getProcessorName(), file.getOriginalFilename());
            Map<String, Object> metadata = doExtractMetadata(inputStream, getFileTypeFromName(file.getOriginalFilename()));
            
            // 添加通用元数据
            addCommonMetadata(metadata, file.getOriginalFilename(), file.getSize());
            return metadata;
        } catch (IOException e) {
            LogUtil.error("元数据提取失败: {}", e, file.getOriginalFilename());
            throw new FileProcessingException("元数据提取失败: " + e.getMessage(), e);
        }
    }

    @Override
    public final Map<String, Object> extractMetadata(FileStorage fileStorage) {
        validateFileStorage(fileStorage);
        
        try {
            LogUtil.info("使用 {} 提取元数据: {}", getProcessorName(), fileStorage.getOriginalFileName());
            Map<String, Object> metadata = doExtractMetadata(new File(fileStorage.getStoragePath()), fileStorage.getFileType());
            
            // 添加通用元数据
            addCommonMetadata(metadata, fileStorage.getOriginalFileName(), fileStorage.getFileSize());
            return metadata;
        } catch (Exception e) {
            LogUtil.error("元数据提取失败: {}", e, fileStorage.getOriginalFileName());
            throw new FileProcessingException("元数据提取失败: " + e.getMessage(), e);
        }
    }

    @Override
    public final boolean validateFormat(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            return false;
        }
        
        String fileName = file.getOriginalFilename();
        if (fileName == null) {
            return false;
        }
        
        String fileType = getFileTypeFromName(fileName);
        if (!supports(fileType)) {
            return false;
        }
        
        try (InputStream inputStream = file.getInputStream()) {
            return doValidateFormat(inputStream, fileType);
        } catch (Exception e) {
            LogUtil.warn("文件格式验证失败: {} - {}", fileName, e.getMessage());
            return false;
        }
    }

    @Override
    public final Map<String, Object> generatePreview(FileStorage fileStorage) {
        Map<String, Object> preview = new HashMap<>();
        
        try {
            preview.putAll(extractMetadata(fileStorage));
            
            // 生成文本预览
            String text = extractText(fileStorage);
            String textPreview = truncateText(text, getPreviewTextLength());
            preview.put("textPreview", textPreview);
            
            // 添加特定类型的预览数据
            Map<String, Object> specificPreview = doGeneratePreview(fileStorage);
            if (specificPreview != null) {
                preview.putAll(specificPreview);
            }
            
        } catch (Exception e) {
            LogUtil.error("预览生成失败: {}", e, fileStorage.getOriginalFileName());
            preview.put("error", "预览生成失败: " + e.getMessage());
        }
        
        return preview;
    }

    /**
     * 子类实现：从输入流提取文本
     */
    protected abstract String doExtractText(InputStream inputStream, String fileType) throws IOException;

    /**
     * 子类实现：从文件提取文本
     */
    protected abstract String doExtractText(File file, String fileType) throws Exception;

    /**
     * 子类实现：从输入流提取元数据
     */
    protected abstract Map<String, Object> doExtractMetadata(InputStream inputStream, String fileType) throws IOException;

    /**
     * 子类实现：从文件提取元数据
     */
    protected abstract Map<String, Object> doExtractMetadata(File file, String fileType) throws Exception;

    /**
     * 子类实现：验证文件格式
     */
    protected abstract boolean doValidateFormat(InputStream inputStream, String fileType) throws Exception;

    /**
     * 子类可选实现：生成特定类型的预览数据
     */
    protected Map<String, Object> doGeneratePreview(FileStorage fileStorage) {
        return new HashMap<>();
    }

    /**
     * 获取预览文本长度限制（子类可重写）
     */
    protected int getPreviewTextLength() {
        return 500;
    }

    /**
     * 验证上传文件
     */
    private void validateFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new FileProcessingException("文件为空");
        }
        
        String fileName = file.getOriginalFilename();
        if (fileName == null) {
            throw new FileProcessingException("文件名为空");
        }
        
        String fileType = getFileTypeFromName(fileName);
        if (!supports(fileType)) {
            throw new FileProcessingException("不支持的文件类型: " + fileType);
        }
    }

    /**
     * 验证存储文件
     */
    private void validateFileStorage(FileStorage fileStorage) {
        if (fileStorage == null) {
            throw new FileProcessingException("文件存储信息为空");
        }
        
        if (!supports(fileStorage.getFileType())) {
            throw new FileProcessingException("不支持的文件类型: " + fileStorage.getFileType());
        }
        
        File file = new File(fileStorage.getStoragePath());
        if (!file.exists()) {
            throw new FileProcessingException("文件不存在: " + fileStorage.getStoragePath());
        }
    }

    /**
     * 从文件名提取文件类型
     */
    protected String getFileTypeFromName(String fileName) {
        if (fileName == null || !fileName.contains(".")) {
            throw new FileProcessingException("无法确定文件类型");
        }
        return fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase();
    }

    /**
     * 截断文本到指定长度
     */
    protected String truncateText(String text, int maxLength) {
        if (text == null) {
            return "";
        }
        if (text.length() <= maxLength) {
            return text;
        }
        return text.substring(0, maxLength) + "...";
    }

    /**
     * 添加通用元数据
     */
    private void addCommonMetadata(Map<String, Object> metadata, String fileName, Long fileSize) {
        metadata.put("fileName", fileName);
        metadata.put("fileSize", fileSize);
        metadata.put("processorName", getProcessorName());
        metadata.put("extractTime", java.time.LocalDateTime.now());
    }
}